﻿using ArtMath.Attribute;
using ArtMath.Component.Point;
using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using ArtMath.Data;
using ArtMath.Resource;
using ArtMath.Setting;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace ArtMath.Component.CoordinateSystem
{
    /// <summary>
    /// 坐标系基类
    /// </summary>
    [Serializable]
    public abstract class CoordinateBase : LineBase
    {
        protected PointD rotatePCenter;
        RPointS originCoordinate;
        public CoordinateBase(SketchPad pad, string name, ToolTypeName toolType) : base(pad, name, toolType, true)
        {
            InPoints = new PointBase[1];
            OriginCoordinate = new RPointS(Pad, (Pad.Canvas.Width / 2).ToString(), (Pad.Canvas.Height / 2).ToString());
            rotatePCenter = OriginCoordinate.ToPointD();
        }
        [MultilingualCategory("Structure")]
        public virtual PointBase OriginPoint
        {
            get { return InPoints[0]; }
            set { SetPoint(0, value); }
        }
        [Browsable(false)]
        protected abstract double ScaleX { get; }
        [Browsable(false)]
        protected abstract double ScaleY { get; }
        [Browsable(false)]
        protected abstract double UnitX { get; }
        [Browsable(false)]
        protected abstract double UnitY { get; }
        [MultilingualCategory("Layout")]
        public virtual RPointS OriginCoordinate
        {
            get { return originCoordinate; }
            set
            {
                if (originCoordinate != null)
                {
                    originCoordinate.CoordinateChanged -= OriginCoordinate_CoordinateChanged;
                }
                originCoordinate = value;
                if (originCoordinate != null)
                {
                    originCoordinate.CoordinateChanged += OriginCoordinate_CoordinateChanged;
                }
            }
        }
        [Browsable(false)]
        public override string Formula
        {
            get
            {
                return base.Formula;
            }
        }
        [Browsable(false)]
        public override PropertyDisplayer FormulaDisplayer
        {
            get
            {
                return base.FormulaDisplayer;
            }

            set
            {
                base.FormulaDisplayer = value;
            }
        }
        public override bool IsEntity
        {
            get
            {
                return false;
            }
        }
        void OriginCoordinate_CoordinateChanged(PointD oldVal, PointD newVal)
        {
            RotateCenter_CoordinateChanged(PointD.Empty, RotateCenter.ToPointD());
            CoordinateChanged(PointsRelocationReason.CoordinateOriginPointTranslated);
        }
        public override void CoordinateSystemTypeChanged()
        {
            //坐标系对坐标系切换事件不作任何反应
        }
        public virtual void CoordinateChanged(PointsRelocationReason reason)
        {
            HashSet<Base> flags = new HashSet<Base>();
            Pad.ForEachObject((Base obj) =>
            {
                if (obj != this)
                {
                    if (flags.Add(obj))
                    {
                        obj.Relocate(reason);
                        //下列代码作用未知
                        //obj.AllRelatedObjectsIterator((Base item) =>
                        //{
                        //    if (flags.Add(item))
                        //    {
                        //        item.Relocate(reason);
                        //    }
                        //    return true;
                        //});
                    }
                }
                return true;
            });
            //foreach (LayerItem item in Pad.Layer.Items)
            //{
            //    if (item.LinkedObj != null && item.LinkedObj != this)
            //    {
            //        ShapeBase shape = item.LinkedObj as ShapeBase;
            //        if (shape != null)
            //        {
            //            if (flags.Add(shape))
            //            {
            //                Base[] rel = shape.GetRelatedObjects();
            //                flags.AddRange(rel);
            //                shape.Relocate(true, reason);
            //                foreach (Base obj in rel)
            //                {
            //                    ShapeBase sb = obj as ShapeBase;
            //                    if (sb != null)
            //                    {
            //                        sb.Relocate(true, reason);
            //                    }
            //                }
            //                //ShapeBase start = null;
            //                //if (shape.IsTop)
            //                //{
            //                //    start = shape;
            //                //}
            //                //else
            //                //{
            //                //    foreach (Base obj in rel)
            //                //    {
            //                //        if (obj is ShapeBase)
            //                //        {
            //                //            start = obj as ShapeBase;
            //                //            break;
            //                //        }
            //                //    }
            //                //}
            //                //Pad.MoveObject_DoMouseDown(start);
            //                //try
            //                //{
            //                //    start.RelocatePoints(false, reason);
            //                //}
            //                //catch (Exception)
            //                //{
            //                //    start.RelocatePoints(true, reason);
            //                //}
            //                //Pad.MoveObject_DoMouseUp(start);
            //            }
            //        }
            //    }
            //}
            //Pad.ClearFlags();
        }
        public override void ComponentChanged(ShapeBase component)
        {
            System.Drawing.Point pt = Pad.PxyToMouseLocation(OriginPoint.Pxy);
            OriginCoordinate.X.SetExpression(pt.X, false);
            OriginCoordinate.Y.SetExpression(pt.Y, false);
            base.ComponentChanged(component);
        }
        public override void RotateAngleChanged(double oldValue)
        {
            base.RotateAngleChanged(oldValue);
            OriginCoordinate.SetFromPointD(OriginCoordinate.ToPointD().RotateAt(rotatePCenter, Pad.GetRad(oldValue - RotateAngle.Value)));
        }
        public override void Delete(bool recoverable = false)
        {
            base.Delete(recoverable);
            Pad.Coordinate = null;
        }
        public override void Recover()
        {
            //坐标系切换应当无条件切换
            //if (Pad.Coordinate == null)
            //{
            //    Pad.Coordinate = this;
            //}
            //else
            //{
            //    DialogResult res = MessageBox.Show(string.Format(Resources.Translate("CoordinateExist"), Pad.Name) + Resources.CommaSeparate + Resources.Translate("ContinueRecover"), Resources.Translate("Ask"), MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
            //    switch (res)
            //    {
            //        case DialogResult.No:
            //            return;
            //        case DialogResult.Cancel:
            //            throw new OperationCanceledException();
            //    }
            //}
            base.Recover();
            Pad.Coordinate = this;
        }
        public override void CreateComponents()
        {
            LineColor = Settings.Instance.AxisColor;
            base.CreateComponents();
        }
        public override void Paint(Graphics gra)
        {
            OriginPoint?.Paint(gra);
        }
        public PointD XYToPxy(PointD xy)
        {
            return new PointD(xy.X * ScaleX / UnitX, -xy.Y * ScaleY / UnitY).Rotate(-RotateAngle.RadValue);
        }
        public PointD PxyToXY(PointD Pxy)
        {
            double cos = Math.Cos(-RotateAngle.RadValue), sin = Math.Sin(-RotateAngle.RadValue),
                D = (cos * cos + sin * sin) * ScaleX * ScaleY,
                Dx = Pxy.X * (cos * ScaleY) + Pxy.Y * (sin * ScaleY),
                Dy = (cos * ScaleX) * Pxy.Y - (sin * ScaleX) * Pxy.X;
            return new PointD(Dx / D * UnitX, -Dy / D * UnitY);
        }
        public double kToPk(double slope)
        {
            return -Math.Tan(Math.Atan(slope * ScaleY / UnitY / ScaleX * UnitX) + RotateAngle.RadValue);
        }
        public double PkTok(double Pslope)
        {
            return Math.Tan(Math.Atan(-Pslope) - RotateAngle.RadValue) * ScaleX / UnitX / ScaleY * UnitY;
        }
        public double RadToPRad(double rad)
        {
            rad = Core.Helper.Angle.StandardizeRad(rad);
            double offset = rad <= Core.Helper.Angle.RightAngle ? Core.Helper.Angle.RadRound : rad > Core.Helper.Angle.RightAngle && rad <= 1.5 * Math.PI ? Math.PI : 0,
                res = offset - Math.Atan(Math.Tan(rad) * ScaleY / UnitY / ScaleX * UnitX) - RotateAngle.RadValue;
            return Core.Helper.Angle.StandardizeRad(res);
        }
        public double DegToPDeg(double degree)
        {
            degree = Core.Helper.Angle.StandardizeDegree(degree);
            double offset = degree <= 90 ? Core.Helper.Angle.DegreeRound : degree > 90 && degree <= 270 ? 180 : 0,
                res = offset - Math.Atan(Math.Tan(degree * Core.Helper.Angle.DToR) * ScaleY / UnitY / ScaleX * UnitX) * Core.Helper.Angle.RToD - RotateAngle.DegreeValue;
            return Core.Helper.Angle.StandardizeDegree(res);
        }
        public double GetPx(double len)
        {
            return len * ScaleX / UnitX;
        }
        public double GetPy(double len)
        {
            return len * ScaleY / UnitY;
        }
        public override void UseFormat(Base obj)
        {
            base.UseFormat(obj);
            if (Settings.Instance.ViewUseFormat)
            {
                CoordinateBase cb = obj as CoordinateBase;
                if (cb != null)
                {
                    OriginCoordinate.SetFromPointD(cb.OriginCoordinate.ToPointD());//不能根据坐标系转换坐标，此处特殊处理
                }
            }
        }
    }
}
